/*
 * Copyright (C) 2012-2013 Michael L.R. Marques
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 * 
 * Contact: michaellrmarques@gmail.com
 */

package com.jm.commons.components.panel;

import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import javax.imageio.ImageIO;
import javax.swing.JPanel;

/**
 * A panel that will display an image as a set style
 * 
 * @author Michael L.R. Marques
 */
public class ImagePanel extends JPanel implements Serializable {
    
    /**
     * The image property support constant
     */
    public static final String PROP_IMAGE_PROPERTY = "image";
    
    /**
     * The image style property support constant
     */
    public static final String PROP_IMAGE_STYLE_PROPERTY = "imageStyle";
    
    /**
     * The image bounds property support constant
     */
    public static final String PROP_IMAGE_BOUNDS_PROPERTY = "imageBounds";
    
    /**
     * The image size property support constant
     */
    public static final String PROP_IMAGE_SIZE_PROPERTY = "imageSize";
    
    /**
     * The image location property support constant
     */
    public static final String PROP_IMAGE_LOCATION_PROPERTY = "imageLocation";
    
    /**
     * This will show the image as normal
     */
    public static final int NONE = 0;
    
    /**
     * This will stretch the image to fit the panel
     */
    public static final int STRETCH = 1;
    
    /**
     * This will place the image in the center
     */
    public static final int CENTER = 2;
    
    /**
     * This will specify that the image be displayed by the image bounds property
     */
    public static final int CUSTOM = 3;
    
    /**
     * The file that the background image will be loaded from
     */
    private File image;
    
    /**
     * The background image that will be rendered to the panel
     */
    private BufferedImage backgroundImage;
    
    /**
     * The style that the image will be rendered
     */
    private int imageStyle = 0;
    
    /**
     * The bounds to which the image will be rendered if the image style is set as custom
     */
    private Rectangle imageBounds;
    
    /**
     * Creates {@code ImagePanel}
     */
    public ImagePanel() {
        super();
        this.imageBounds = new Rectangle(0, 0 , 0 , 0);
    }
    
    /**
     * Gets the image
     * 
     * @return BufferedImage
     */
    public File getImage() {
        return this.image;
    }
    
    /**
     * Sets the image from a file object
     * 
     * @param file 
     */
    public void setImage(File image) {
        // Check if the file exists
        if (image == null ||
                !image.exists()) {
            return;
        }
        // Set the background image
        try {
            this.backgroundImage = ImageIO.read(image);
        } catch (IOException ioe) {
            System.out.println(ioe);
            return;
        }
        super.firePropertyChange(PROP_IMAGE_PROPERTY, this.image, image);
        this.image = image;
        this.imageBounds = new Rectangle(0, 0, this.backgroundImage.getWidth(), this.backgroundImage.getHeight());
        this.paintComponent(getGraphics());
    }
    
    /**
     * Gets the image
     * 
     * @return 
     */
    public int getImageStyle() {
        return this.imageStyle;
    }
    
    /**
     * Sets the images style
     * 
     * @param imageStyle 
     */
    public void setImageStyle(int imageStyle) {
        super.firePropertyChange(PROP_IMAGE_STYLE_PROPERTY, this.imageStyle, imageStyle);
        this.imageStyle = imageStyle;
        this.paintComponent(getGraphics());
    }
    
    /**
     * Gets the bounds of the image
     * 
     * @return 
     */
    public Rectangle getImageBounds() {
        return this.imageBounds;
    }
    
    /**
     * Sets the bounds of the image
     * 
     * @param imageBounds 
     */
    public void setImageBounds(Rectangle imageBounds) {
        super.firePropertyChange(PROP_IMAGE_BOUNDS_PROPERTY, this.imageBounds, imageBounds);
        this.imageBounds = imageBounds;
        this.paintComponent(getGraphics());
    }
    
    /**
     * Gets the images size
     * 
     * @return 
     */
    public Dimension getImageSize() {
        return this.imageBounds.getSize();
    }
    
    /**
     * Sets the images size
     * 
     * @param size 
     */
    public void setImageSize(Dimension size) {
        super.firePropertyChange(PROP_IMAGE_SIZE_PROPERTY, this.imageBounds.getSize(), size);
        this.imageBounds.setSize(size);
        this.paintComponent(getGraphics());
    }
    
    /**
     * Gets the images location
     * 
     * @return 
     */
    public Point getImageLocation() {
        return this.imageBounds.getLocation();
    }
    
    /**
     * Sets the images location
     * 
     * @param location 
     */
    public void setImageLocation(Point location) {
        super.firePropertyChange(PROP_IMAGE_LOCATION_PROPERTY, this.imageBounds.getLocation(), location);
        this.imageBounds.setLocation(location);
        this.paintComponent(getGraphics());
    }
    
    /**
     * Gets the images x position
     * 
     * @return 
     */
    public int getImageX() {
        return this.imageBounds.x;
    }
    
    /**
     * Gets the images y position
     * 
     * @return 
     */
    public int getImageY() {
        return this.imageBounds.y;
    }
    
    /**
     * Gets the images width
     * 
     * @return 
     */
    public int getImageWidth() {
        return this.imageBounds.width;
    }
    
    /**
     * Gets the images height
     * 
     * @return 
     */
    public int getImageHeight() {
        return this.imageBounds.height;
    }
    
    /**
     * Overrides the {@code abstract paintComponent(Graphics g)} method
     * to paint an image on this component
     * @param g
     */
    @Override protected void paintComponent(Graphics g) {
        // If the graphics objecct is not null paint the image
        if (g != null) {
            // Check if the image is null, if it is, paint as usual
            if (this.backgroundImage == null) {
                super.paintComponent(g);
                return;
            }
            // If opaque is set to on, then set the background colour to the graphics object
            if (this.isOpaque()) {
                g.setColor(this.getBackground());
            }
            // Paint the colour to the graphics object
            g.fillRect(0, 0, this.getWidth(), this.getHeight());
            // Paint the image according to the style
            switch (this.imageStyle) {
                case STRETCH: {
                    g.drawImage(this.backgroundImage, 0, 0, this.getWidth(), this.getHeight(), this);
                    break;
                } case CENTER: {
                    g.drawImage(this.backgroundImage, this.getWidth()/2 - this.backgroundImage.getWidth()/2, this.getHeight()/2 - this.backgroundImage.getHeight()/2, this.backgroundImage.getWidth(), this.backgroundImage.getHeight(), this);
                    break;
                } case CUSTOM: {
                    g.drawImage(this.backgroundImage, this.imageBounds.x, this.imageBounds.y, this.imageBounds.width, this.imageBounds.height, this);
                    break;
                } case NONE: {
                } default : {
                    g.drawImage(this.backgroundImage, 0, 0, this.backgroundImage.getWidth(), this.backgroundImage.getHeight(), this);
                    break;
                }
            }
        }
    }
    
}
